;; collection/u8vector.scm - (c) rohan drape, 2001-2004

;; A <u8vector> is a homogenous vector of unsigned eight-bit integers.
;; It is defined by SRFI-4.

;; Equality predicate. 

(define (u8vector=? a b)
  (let ((l (u8vector-length a)))
    (and (= l (u8vector-length b))
	 (let loop ((i 0))
	   (if (= i l)
	       #t
	       (if (= (u8vector-ref a i) 
		      (u8vector-ref b i))
		   (loop (+ i 1))
		   #f))))))

;; Embed the <u8vector> source into the <u8vector> destination at the
;; <integer> index.

(define (u8vector-copy! destination index source)
  (let ((source-length (u8vector-length source)))
    (let loop ((i index)
	       (j 0))
      (if (= j source-length)
	  destination
	  (begin
	    (u8vector-set! destination i (u8vector-ref source j))
	    (loop (+ i 1) (+ j 1)))))))

;; Return a <u8vector> that is a concatenation of the list of
;; <u8vector>s at `input'.

(define (u8vector-append . input)
  (define (calculate-size input size)
    (if (null? input)
	size
	(calculate-size (cdr input)
			(+ size (u8vector-length (car input))))))
  (let* ((total-size (calculate-size input 0))
	 (result (make-u8vector total-size)))
    (let loop ((rest input) 
	       (index 0))
      (if (null? rest)
	  result
	  (begin
	    (u8vector-copy! result index (car rest))
	    (loop (cdr rest)
		  (+ index (u8vector-length (car rest)))))))))

;; Apply u8vector-append to the <list> l.

(define (u8vector-concatenate l)
  (apply u8vector-append l))

;; Return a <u8vector> that has the elements of `b' from `start' to
;; `end'.

(define (u8vector-copy b start end)
  (let* ((interval (- end start))
	 (result (make-u8vector interval)))
    (do ((i 0 (+ i 1))
	 (j start (+ j 1)))
	((>= i interval) result)
      (u8vector-set! result i (u8vector-ref b j)))))

;; Procedures where the string variant takes or returns <char>'s here
;; take or return <integer>'s.

(define (u8vector-index b k)
  (let ((start 0)
	(end (u8vector-length b)))
    (let loop ((i start))
      (and (< i end)
	   (if (= k (u8vector-ref b i))
	       i
	       (loop (+ i 1)))))))

(define (u8vector-index-right b k) 
  (let ((start 0)
	(end (u8vector-length b)))
    (let loop ((i (- end 1)))
      (and (>= i start)
	   (if (= k (u8vector-ref b i)) 
	       i
	       (loop (- i 1)))))))
  
;; Conversion to <string> collection type.  The inverse is not a safe
;; operation.

(define (u8vector->string v) 
  (let* ((l (u8vector-length v))
	 (s (make-string l)))
    (do ((i 0 (+ i 1)))
	((= i l))
      (string-set! s i (integer->char (u8vector-ref v i))))
    s))

;; This is an unsafe operation!  It is provided because some protocols
;; encode human readable strings as byte strings.  Be very careful
;; using this procedure.

(define (string->u8vector s)
  (let* ((l (string-length s))
	 (v (make-u8vector l)))
    (do ((i 0 (+ i 1)))
	((= i l))
      (u8vector-set! v i (char->integer (string-ref s i))))
    v))

